﻿#pragma once
#include "OpenGL项目主标头.h"
#include "OpenGL纹理类标头.h"

#define STB_IMAGE_IMPLEMENTATION    // 包含 stb_image.h 头文件时需要先定义此宏
#include "header/stblib/stb_image.h"
// C/C++ 标准库学习网站：https://legacy.cplusplus.com
// C/C++ 参考学习网站：https://zh.cppreference.com/w/cpp
// C/C++ 微软(Visual Studio)中文学习网站：https://learn.microsoft.com/zh-cn/cpp/cpp/?view=msvc-170
// OpenGl 学习网站：https://www.khronos.org/opengl/wiki
// OpenGl 的 GLFW 学习网站：https://www.glfw.org/docs/latest/glfw3_8h.html#ac06b663d79c8fcf04669cc8fcc0b7670
// OpenGl 的 GLEW 学习网站：https://docs.gl/
// stb 仓库的地址 https://github.com/nothings/stb

/*
纹理的格式主要有内部格式和格式：
	内部格式是 OpenGL 用到的纹理数据格式，例如：GL_RGB, GL_RGBA, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, GL_RED, GL_RG, GL_RGB, GL_RGBA, GL_SRGB, GL_SRGB_ALPHA, GL_R8, GL_RG8, GL_RGB8, GL_RGBA8, GL_R16F, GL_RGB16F, GL_RGBA16F, GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F, GL_R8I, GL_RG8I, GL_RGB8I, GL_RGBA8I, GL_R16I, GL_RG16I, GL_RGB16I, GL_RGBA16I, GL_R32I, GL_RG32I, GL_RGB32I 等
	格式是 OpenGL 用来指定纹理数据存储格式的，例如：GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_RED_INTEGER, GL_RG_INTEGER, GL_RGB_INTEGER, GL_BGR_INTEGER, GL_RGBA_INTEGER, GL_BGRA_INTEGER, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, GL_DEPTH_COMPONENT32F, GL_DEPTH32F_STENCIL8 等

纹理的加载方式主要有：
	从文件加载：stbi_load() 函数，可以加载常见的图片格式，例如：jpg, png, bmp, tga, gif, ico, psd, hdr, pic, jxr, hdp, psx, nvx, ktx, astc, dds, pvr, ktx, pkm, ktx, k
	从内存加载：glTexImage2D() 函数，可以加载纹理数据到内存中，并指定纹理的格式和大小
	从屏幕加载：glReadPixels() 函数，可以从屏幕上读取像素数据，并加载到纹理中
	从纹理加载：glCopyTexImage2D() 函数，可以从另一个纹理对象中拷贝纹理数据到当前纹理对象中

纹理的过滤方式主要有：
	线性过滤：GL_LINEAR，平滑地插值纹理，适用于图像模糊，边缘锐化等效果
	邻近过滤：GL_NEAREST，采用最近邻的像素值，不考虑距离，适用于图像平滑，边缘锐化等效果
	双线性过滤：GL_LINEAR_MIPMAP_LINEAR，先对纹理进行双线性插值，再进行一次线性插值，适用于图像模糊，边缘锐化等效果
	双三次过滤：GL_LINEAR_MIPMAP_NEAREST，先对纹理进行双线性插值，再进行一次邻近插值，适用于图像模糊，边缘锐化等效果
	三次过滤：GL_NEAREST_MIPMAP_LINEAR，先对纹理进行邻近插值，再进行一次线性插值，适用于图像平滑，边缘锐化等效果
	三次邻近过滤：GL_NEAREST_MIPMAP_NEAREST，先对纹理进行邻近插值，再进行一次邻近插值，适用于图像平滑，边缘锐化等效果

纹理的包裹方式主要有：
	GL_REPEAT：重复纹理，超出纹理坐标范围时，会重复纹理的边缘像素
	GL_CLAMP_TO_EDGE：纹理坐标超过范围时，会重复纹理的边缘像素
	GL_CLAMP_TO_BORDER：纹理坐标超过范围时，会使用边缘颜色填充
	GL_MIRRORED_REPEAT：重复纹理，超出纹理坐标范围时，会镜像重复纹理的边缘像素

纹理的环绕方式主要有：
	GL_REPEAT：重复纹理，超出纹理坐标范围时，会重复纹理的边缘像素
	GL_CLAMP_TO_EDGE：纹理坐标超过范围时，会重复纹理的边缘像素
	GL_MIRRORED_REPEAT：重复纹理，超出纹理坐标范围时，会镜像重复纹理的边缘像素

纹理的边缘锐化模式主要有：
	GL_ZERO：不进行边缘锐化
	GL_ONE：边缘锐化，边缘像素的颜色值设置为 1.0
	GL_SRC_COLOR：边缘锐化，边缘像素的颜色值设置为源像素的颜色值
	GL_ONE_MINUS_SRC_COLOR：边缘锐化，边缘像素的颜色值设置为 1.0 - 源像素的颜色值
	GL_DST_COLOR：边缘锐化，边缘像素的颜色值设置为目标像素的颜色值
	GL_ONE_MINUS_DST_COLOR：边缘锐化，边缘像素的颜色值设置为 1.0 - 目标像素的颜色值
	GL_SRC_ALPHA：边缘锐化，边缘像素的颜色值设置为源像素的 alpha 值
	GL_ONE_MINUS_SRC_ALPHA：边缘锐化，边缘像素的颜色值设置为 1.0 - 源像素的 alpha 值
	GL_DST_ALPHA：边缘锐化，边缘像素的颜色值设置为目标像素的 alpha 值
	GL_ONE_MINUS_DST_ALPHA：边缘锐化，边缘像素的颜色值设置为 1.0 - 目标像素的 alpha 值
	GL_CONSTANT_COLOR：边缘锐化，边缘像素的颜色值设置为常量颜色值
	GL_ONE_MINUS_CONSTANT_COLOR：边缘锐化，边缘像素的颜色值设置为 1.0 - 常量颜色值
	GL_CONSTANT_ALPHA：边缘锐化，边缘像素的颜色值设置为常量 alpha 值
	GL_ONE_MINUS_CONSTANT_ALPHA：边缘锐化，边缘像素的颜色值设置为 1.0 - 常量 alpha 值
	GL_SRC_ALPHA_SATURATE：边缘锐化，边缘像素的颜色值设置为源像素的 alpha 值，如果源像素的 alpha 值大于 0.5，则边缘像素的颜色值设置为 1.0，否则设置为 0.0

纹理的深度比较方式主要有：
	GL_LESS：深度比较，如果当前像素的深度值小于深度缓存中的值，则通过测试
	GL_LEQUAL：深度比较，如果当前像素的深度值小于等于深度缓存中的值，则通过测试
	GL_EQUAL：深度比较，如果当前像素的深度值等于深度缓存中的值，则通过测试
	GL_GEQUAL：深度比较，如果当前像素的深度值大于等于深度缓存中的值，则通过测试
	GL_GREATER：深度比较，如果当前像素的深度值大于深度缓存中的值，则通过测试
	GL_NOTEQUAL：深度比较，如果当前像素的深度值不等于深度缓存中的值，则通过测试

纹理的深度写入方式主要有：
	GL_DEPTH_COMPONENT：深度写入，将深度值写入深度缓存中
	GL_STENCIL_INDEX：模板写入，将模板值写入模板缓存中
	GL_DEPTH_STENCIL：深度模板写入，将深度值和模板值写入深度模板缓存中

纹理的压缩方式主要有：
	GL_COMPRESSED_RGB_S3TC_DXT1_EXT：压缩纹理，采用 DXT1 压缩算法，适用于 RGB 纹理
	GL_COMPRESSED_RGBA_S3TC_DXT1_EXT：压缩纹理，采用 DXT1 压缩算法，适用于 RGBA 纹理
	GL_COMPRESSED_RGBA_S3TC_DXT3_EXT：压缩纹理，采用 DXT3 压缩算法，适用于 RGBA 纹理
	GL_COMPRESSED_RGBA_S3TC_DXT5_EXT：压缩纹理，采用 DXT5 压缩算法，适用于 RGBA 纹理
	GL_COMPRESSED_SRGB_S3TC_DXT1_EXT：压缩纹理，采用 DXT1 压缩算法，适用于 sRGB 纹理
	GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT：压缩纹理，采用 DXT1 压缩算法，适用于 sRGB 纹理
	GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT：压缩纹理，采用 DXT3 压缩算法，适用于 sRGB 纹理
	GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT：压缩纹理，采用 DXT5 压缩算法，适用于 sRGB 纹理
	GL_COMPRESSED_RED_RGTC1_EXT：压缩纹理，采用 RGTC1 压缩算法，适用于 R 纹理
	GL_COMPRESSED_SIGNED_RED_RGTC1_EXT：压缩纹理，采用 RGTC1 压缩算法，适用于 R 纹理，采用符号压缩
	GL_COMPRESSED_RG_RGTC2_EXT：压缩纹理，采用 RGTC2 压缩算法，适用于 RG 纹理
	GL_COMPRESSED_SIGNED_RG_RGTC2_EXT：压缩纹理，采用 RGTC2 压缩算法，适用于 RG 纹理，采用符号压缩
	GL_COMPRESSED_RGBA_BPTC_UNORM_ARB：压缩纹理，采用 BPTC 压缩算法，适用于 RGBA 纹理
	GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB：压缩纹理，采用 BPTC 压缩算法，适用于 sRGB 纹理
	GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB：压缩纹理，采用 BPTC 压缩算法，适用于 RGB 纹理，采用符号压缩
	GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB：压缩纹理，采用 BPTC 压缩算法，适用于 RGB 纹理，采用无符号压缩

纹理的采样器类型主要有：
	GL_TEXTURE_1D：一维纹理采样器
	GL_TEXTURE_2D：二维纹理采样器
	GL_TEXTURE_3D：三维纹理采样器
	GL_TEXTURE_CUBE_MAP：立方体纹理采样器
	GL_TEXTURE_1D_ARRAY：一维纹理数组采样器
	GL_TEXTURE_2D_ARRAY：二维纹理数组采样器
	GL_TEXTURE_RECTANGLE：矩形纹理采样器
	GL_TEXTURE_BUFFER：缓冲纹理采样器
	GL_TEXTURE_CUBE_MAP_ARRAY：立方体纹理数组采样器
	GL_TEXTURE_2D_MULTISAMPLE：多采样二维纹理采样器
	GL_TEXTURE_2D_MULTISAMPLE_ARRAY：多采样二维纹理数组采样器
	GL_TEXTURE_CUBE_MAP_POSITIVE_X：立方体纹理采样器，正面朝上
	GL_TEXTURE_CUBE_MAP_NEGATIVE_X：立方体纹理采样器，反面朝上
	GL_TEXTURE_CUBE_MAP_POSITIVE_Y：立方体纹理采样器，正面朝上
	GL_TEXTURE_CUBE_MAP_NEGATIVE_Y：立方体纹理采样器，反面朝上
	GL_TEXTURE_CUBE_MAP_POSITIVE_Z：立方体纹理采样器，正面朝上
	GL_TEXTURE_CUBE_MAP_NEGATIVE_Z：立方体纹理采样器，反面朝上

纹理的采样器参数主要有：
	GL_TEXTURE_MIN_FILTER：纹理缩小过滤方式
	GL_TEXTURE_MAG_FILTER：纹理放大过滤方式
	GL_TEXTURE_WRAP_S：纹理水平方向包裹方式
	GL_TEXTURE_WRAP_T：纹理垂直方向包裹方式
	GL_TEXTURE_WRAP_R：纹理深度方向包裹方式
	GL_TEXTURE_BASE_LEVEL：纹理的最小 mipmap 层级
	GL_TEXTURE_MAX_LEVEL：纹理的最大 mipmap 层级
	GL_TEXTURE_SWIZZLE_R：纹理的 R 通道输入
	GL_TEXTURE_SWIZZLE_G：纹理的 G 通道输入
	GL_TEXTURE_SWIZZLE_B：纹理的 B 通道输入
	GL_TEXTURE_SWIZZLE_A：纹理的 A 通道输入
	GL_TEXTURE_BORDER_COLOR：纹理的边缘颜色
	GL_TEXTURE_COMPARE_MODE：纹理的深度比较模式
	GL_TEXTURE_COMPARE_FUNC：纹理的深度比较函数
	GL_DEPTH_STENCIL_TEXTURE_MODE：深度模板纹理的深度和模板写入模式
	GL_TEXTURE_IMMUTABLE_FORMAT：纹理的不可变格式
	GL_TEXTURE_IMMUTABLE_LEVELS：纹理的不可变层级
	GL_TEXTURE_LOD_BIAS：纹理的 mipmap 层级偏移量
	GL_TEXTURE_MIN_LOD：纹理的最小 mipmap 层级
	GL_TEXTURE_MAX_LOD：纹理的最大 mipmap 层级
	GL_TEXTURE_MAX_ANISOTROPY：纹理的最大各向异性
	GL_TEXTURE_SRGB_DECODE_EXT：sRGB 纹理的解码模式
	GL_TEXTURE_SWIZZLE_RGBA：纹理的 RGBA 输入
	GL_TEXTURE_VIEW_MIN_LEVEL：纹理视图的最小 mipmap 层级
	GL_TEXTURE_VIEW_NUM_LEVELS：纹理视图的 mipmap 层级数量
	GL_TEXTURE_VIEW_MIN_LAYER：纹理视图的最小层级
	GL_TEXTURE_VIEW_NUM_LAYERS：纹理视图的层级数量
	GL_TEXTURE_IMMUTABLE_LEVELS：纹理的不可变层级
	GL_TEXTURE_VIEW_COMPATIBILITY_CLASS：纹理视图的兼容性类
纹理的采样器参数的设置方式主要有：
	直接设置：glTexParameteri() 函数，设置纹理的缩小过滤方式，放大过滤方式，水平方向包裹方式，垂直方向包裹方式，深度方向包裹方式，最小 mipmap 层级，最大 mipmap 层级，深度比较模式，深度比较函数，深度模板写入模式，不可变格式，不可变层级，mipmap 层级偏移量，最小 mipmap 层级，最大 mipmap 层级，最大各向异性，sRGB 纹理解码模式，RGBA 输入，最小 mipmap 层级，mipmap 层级数量，最小层级，层级数量，不可变层级，兼容性类
	通过函数设置：glTexParameterf() 函数，设置纹理的各项参数，包括缩小过滤方式，放大过滤方式，水平方向包裹方式，垂直方向包裹方式，深度方向包裹方式，最小 mipmap 层级，最大 mipmap 层级，深度比较模式，深度比较函数，深度模板写入模式，不可变格式，不可变层级，mipmap 层级偏移量，最小 mipmap 层级，最大 mipmap 层级，最大各向异性，sRGB 纹理解码模式，RGBA 输入，最小 mipmap 层级，mipmap 层级数量，最小层级，层级数量，不可变层级，兼容性类
	通过函数获取：glGetTexParameteriv() 函数，获取纹理的各项参数，包括缩小过滤方式，放大过滤方式，水平方向包裹方式，垂直方向包裹方式，深度方向包裹方式，最小 mipmap 层级，最大 mipmap 层级，深度比较模式，深度比较函数，深度模板写入模式，不可变格式，不可变层级，mipmap 层级偏移量，最小 mipmap 层级，最大 mipmap 层级，最大各向异性，sRGB 纹理解码模式，RGBA 输入，最小 mipmap 层级，mipmap 层级数量，最小层级，层级数量，不可变层级，兼容性类
	通过函数获取：glGetTexParameterfv() 函数，获取纹理的各项参数，包括缩小过滤方式，放大过滤方式，水平方向包裹方式，垂直方向包裹方式，深度方向包裹方式，最小 mipmap 层级，最大 mipmap 层级，深度比较模式，深度比较函数，深度模板写入模式，不可变格式，不可变层级，mipmap 层级偏移量，最小 mipmap 层级，最大 mipmap 层级，最大各向异性，sRGB 纹理解码模式，RGBA 输入，最小 mipmap 层级，mipmap 层级数量，最小层级，层级数量，不可变层级，兼容性类

纹理的采样器参数的设置示例：
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 设置纹理的缩小过滤方式为线性插值（纹理模拟的方式），第三个参数表示线性重新采样
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 这里第二个参数设置纹理的放大过滤方式为线性插值（因为渲染纹理时会比实际的纹理大小更大，所以需要放大）
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); // 设置纹理水平方向为嵌入模式，即纹理坐标超过范围时，会重复纹理的边缘像素（理解为不希望扩大纹理区域，并平铺纹理）
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); // 设置纹理的垂直方向重复模式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // 设置纹理的水平方向重复模式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); // 设置纹理的深度比较模式为比较模式，即比较纹理与深度缓冲区的深度值
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); // 设置纹理的深度比较函数为小于等于，即深度值小于等于深度缓冲区的深度值时，通过测试，否则不通过测试
	glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT); // 设置深度模板纹理的深度和模板写入模式，这里设置纹理的深度值写入深度缓冲区，模板值写入模板缓冲区
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_FORMAT, GL_TRUE); // 设置纹理的不可变格式，即纹理的格式不能被改变
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_LEVELS, 1); // 设置纹理的不可变层级，即纹理的 mipmap 层级不能被改变
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f); // 设置纹理的 mipmap 层级偏移量，这里设置偏移量为 0.0f
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, -1000.0f); // 设置纹理的最小 mipmap 层级，这里设置最小层级为 -1000.0f
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 1000.0f); // 设置纹理的最大 mipmap 层级，这里设置最大层级为 1000.0f
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 16.0f); // 设置纹理的最大各向异性，这里设置最大各向异性为 16.0f
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); // 设置纹理的 R 通道输入，这里设置 R 通道输入为红色通道
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN); // 设置纹理的 G 通道输入，这里设置 G 通道输入为绿色通道
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE); // 设置纹理的 B 通道输入，这里设置 B 通道输入为蓝色通道
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); // 设置纹理的 A 通道输入，这里设置 A 通道输入为透明度通道
	glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(glm::vec4(0.0f))); // 设置纹理的边缘颜色，这里设置边缘颜色为黑色
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT); // 设置 sRGB 纹理的解码模式，这里设置解码模式为 GL_DECODE_EXT
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, GL_RGBA); // 设置纹理的 RGBA 输入，这里设置 RGBA 输入为 RGBA 通道
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_VIEW_MIN_LEVEL, 0); // 设置纹理视图的最小 mipmap 层级，这里设置最小层级为 0
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_VIEW_NUM_LEVELS, 1); // 设置纹理视图的 mipmap 层级数量，这里设置 mipmap 层级数量为 1
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_VIEW_MIN_LAYER, 0); // 设置纹理视图的最小层级，这里设置最小层级为 0
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_VIEW_NUM_LAYERS, 1); // 设置纹理视图的层级数量，这里设置层级数量为 1
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_LEVELS, 1); // 设置纹理的不可变层级，这里设置不可变层级为 1
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_VIEW_COMPATIBILITY_CLASS, GL_TEXTURE_VIEW_CLASS_2D); // 设置纹理视图的兼容性类，这里设置兼容性类为 2D 纹理视图
*/

Texture::Texture(const std::string& filename, uint32_t id)
	: m_id(id), m_texture_renderer_id(0), m_file_path(filename),
	m_width(0), m_height(0), m_bits_per_pixel(0) { // load texture from file
	// set the texture wrapping parameters
	stbi_set_flip_vertically_on_load(true); // 垂直翻转纹理，以适应 OpenGL 的坐标系（OpenGL需要从左下角开始绘制，而图片一般是从左上角开始绘制的）

	m_local_buffer = stbi_load(filename.c_str(), &m_width, &m_height, &m_bits_per_pixel, 4); // 加载图片数据到内存中，最后一个参数表示颜色通道数（这里选择 rgba 四通道）

	// 加载图像
	int width, height, nr_channels;
	m_local_buffer = stbi_load(filename.c_str(), &width, &height, &nr_channels, 0);

	gl_call(glGenTextures(m_id, &m_texture_renderer_id)); // 
	gl_call(glBindTexture(GL_TEXTURE_2D, m_texture_renderer_id)); // 绑定纹理对象，并设置其为当前激活纹理对象，GL_TEXTURE_2D 表示 2d 纹理

	// 设置纹理包裹设置纹理过滤参数
	gl_call(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); // 第二个参数设置纹理的缩小过滤方式为线性插值（纹理模拟的方式），第三个参数表示线性重新采样
	gl_call(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); // 这里第二个参数设置纹理的放大过滤方式为线性插值（因为渲染纹理时会比实际的纹理大小更大，所以需要放大）
	gl_call(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); // 设置纹理水平方向为嵌入模式，即纹理坐标超过范围时，会重复纹理的边缘像素（理解为不希望扩大纹理区域，并平铺纹理）
	gl_call(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); // 设置纹理的垂直方向重复模式
	gl_call(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); // 设置纹理的水平方向重复模式

	// 创建纹理和生成贴图
	if (m_local_buffer) {
		m_width = width;					// 图片宽度
		m_height = height;					// 图片高度
		m_bits_per_pixel = nr_channels * 8; // 8 位

		//gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m_width, m_height, 0, GL_RGB, GL_UNSIGNED_BYTE, m_local_buffer)); // 加载纹理数据到纹理对象
		gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_local_buffer)); // 加载纹理数据到纹理对象，注意 png 格式图片才支持 rgba

		gl_call(glGenerateMipmap(GL_TEXTURE_2D)); // 生成 mipmap 贴图，用于纹理的自适应缩小
		//gl_call(glGenerateTextureMipmap(GL_TEXTURE_2D));

		stbi_image_free(m_local_buffer); // 释放内存
	}
	else
		printf("Failed to load texture");
	//std::cout << "Failed to load texture" << std::endl;

	gl_call(glBindTexture(GL_TEXTURE_2D, 0)); // 解绑纹理对象
}

Texture::~Texture() {
	printf("Texture destructor called, deleting texture object %d\n", m_texture_renderer_id);
	gl_call(glDeleteTextures(m_id, &m_texture_renderer_id)); // 删除纹理对象
}

void Texture::bind(unsigned char slot) const {
	gl_call(glActiveTexture(GL_TEXTURE0 + slot)); // 设置纹理单元，GL_TEXTURE0 表示第一个纹理单元插槽，windows 一般有 32 个插槽，手机一般是 8 个
	gl_call(glBindTexture(GL_TEXTURE_2D, m_texture_renderer_id)); // 绑定纹理对象
}

void Texture::unbind() const {
	gl_call(glBindTexture(GL_TEXTURE_2D, 0)); // 解绑纹理对象
}
